package cn.iocoder.yudao.module.energy.service.alert;

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import cn.iocoder.yudao.module.energy.controller.admin.alert.vo.*;
import cn.iocoder.yudao.module.energy.controller.admin.statistics.vo.StatisticsRespVO;
import cn.iocoder.yudao.module.energy.dal.dataobject.alert.EnergyAlertDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.energy.dal.mysql.alert.AlertMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.energy.enums.ErrorCodeConstants.*;

import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 预警 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class AlertServiceImpl implements AlertService {

    @Resource
    private AlertMapper alertMapper;

    @Override
    public Long createAlert(AlertSaveReqVO createReqVO) {
        // 插入
        EnergyAlertDO alert = BeanUtils.toBean(createReqVO, EnergyAlertDO.class);
        alertMapper.insert(alert);
        // 返回
        return alert.getId();
    }

    @Override
    public void updateAlert(AlertSaveReqVO updateReqVO) {
        // 校验存在
        validateAlertExists(updateReqVO.getId());
        // 更新
        EnergyAlertDO updateObj = BeanUtils.toBean(updateReqVO, EnergyAlertDO.class);
        alertMapper.updateById(updateObj);
    }

    @Override
    public void deleteAlert(Long id) {
        // 校验存在
        validateAlertExists(id);
        // 删除
        alertMapper.deleteById(id);
    }

    private void validateAlertExists(Long id) {
        if (alertMapper.selectById(id) == null) {
            throw exception(ALERT_NOT_EXISTS);
        }
    }

    @Override
    public EnergyAlertDO getAlert(Long id) {
        return alertMapper.selectById(id);
    }

    @Override
    public PageResult<EnergyAlertDO> getAlertPage(AlertPageReqVO pageReqVO) {
        return alertMapper.selectPage(pageReqVO);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreateAlerts(List<EnergyAlertDO> alerts) {
        if (alerts.isEmpty()) {
            return;
        }
        
        // 批量插入
        for (EnergyAlertDO alert : alerts) {
            alertMapper.insert(alert);
        }
    }

    /**
     * 获取指定时间范围内的告警数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 告警数量
     */
    @Override
    public Long getAlertCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内的告警数量
        return alertMapper.selectCountByCreateTimeBetween(startTime, endTime);
    }

    /**
     * 获取总告警数量
     *
     * @return 总告警数量
     */
    @Override
    public Long getTotalAlertCount() {
        // 查询数据库，获取总告警数量
        return alertMapper.selectCount();
    }
    
    /**
     * 获取指定时间范围内各类型预警的数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 各类型预警的数量统计，key 为预警类型，value 为数量
     */
    @Override
    public Map<String, Long> getAlertTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内各类型预警的数量
        List<Map<String, Object>> result = alertMapper.selectAlertTypeCountByCreateTimeBetween(startTime, endTime);
        
        // 将结果转换为Map<String, Long>格式
        Map<String, Long> alertTypeCount = new HashMap<>();
        for (Map<String, Object> map : result) {
            String alertType = (String) map.get("alert_type");
            Long count = ((Number) map.get("count")).longValue();
            alertTypeCount.put(alertType, count);
        }
        
        return alertTypeCount;
    }
    
    /**
     * 获取指定时间范围内每天各类型预警的数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每天各类型预警的数量统计列表
     */
    @Override
    public List<StatisticsRespVO.DailyAlertTypeCountVO> getDailyAlertTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内每天各类型预警的数量
        List<Map<String, Object>> result = alertMapper.selectDailyAlertTypeCountByCreateTimeBetween(startTime, endTime);
        
        // 获取所有预警类型
        Set<String> allAlertTypes = new HashSet<>();
        for (Map<String, Object> row : result) {
            String alertType = (String) row.get("alert_type");
            allAlertTypes.add(alertType);
        }
        
        // 按日期分组整理数据
        Map<String, Map<String, Long>> groupedByDate = new HashMap<>();
        
        // 处理查询结果
        for (Map<String, Object> row : result) {
            String dateStr = row.get("date").toString();
            String alertType = (String) row.get("alert_type");
            Long count = ((Number) row.get("count")).longValue();
            
            // 按日期分组
            groupedByDate.computeIfAbsent(dateStr, k -> new HashMap<>())
                    .put(alertType, count);
        }
        
        // 转换为返回格式
        List<StatisticsRespVO.DailyAlertTypeCountVO> dailyAlertTypeCounts = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        
        // 收集时间范围内所有的日期
        Set<LocalDate> allDates = new HashSet<>();
        LocalDate currentDate = startTime.toLocalDate();
        LocalDate endDate = endTime.toLocalDate();
        
        while (!currentDate.isAfter(endDate)) {
            allDates.add(currentDate);
            currentDate = currentDate.plusDays(1);
        }
        
        // 为每个日期创建记录
        for (LocalDate date : allDates) {
            String dateStr = date.format(formatter);
            StatisticsRespVO.DailyAlertTypeCountVO vo = new StatisticsRespVO.DailyAlertTypeCountVO();
            vo.setDate(date);
            
            // 获取该日期的数据，如果不存在则创建一个空的
            Map<String, Long> typeCounts = groupedByDate.getOrDefault(dateStr, new HashMap<>());
            
            // 确保所有预警类型都有值，没有的设为0
            for (String alertType : allAlertTypes) {
                typeCounts.putIfAbsent(alertType, 0L);
            }
            
            vo.setAlertTypeCounts(typeCounts);
            dailyAlertTypeCounts.add(vo);
        }
        
        // 按日期排序
        dailyAlertTypeCounts.sort(Comparator.comparing(StatisticsRespVO.DailyAlertTypeCountVO::getDate));
        
        return dailyAlertTypeCounts;
    }

    /**
     * 获取指定时间范围内按月统计各类型预警的数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每月各类型预警的数量统计列表
     */
    @Override
    public List<StatisticsRespVO.DailyAlertTypeCountVO> getMonthlyAlertTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内每月各类型预警的数量
        List<Map<String, Object>> result = alertMapper.selectMonthlyAlertTypeCountByCreateTimeBetween(startTime, endTime);
        
        // 将结果按年月分组整理
        Map<String, Map<String, Long>> groupedByMonth = new HashMap<>();
        
        // 处理查询结果
        for (Map<String, Object> row : result) {
            Integer year = ((Number) row.get("year")).intValue();
            Integer month = ((Number) row.get("month")).intValue();
            String alertType = (String) row.get("alert_type");
            Long count = ((Number) row.get("count")).longValue();
            
            // 组合年月键
            String monthKey = String.format("%d-%02d", year, month);
            
            // 按年月分组
            groupedByMonth.computeIfAbsent(monthKey, k -> new HashMap<>())
                    .put(alertType, count);
        }
        
        // 准备返回数据的月份列表
        List<String> monthsToReturn = new ArrayList<>();
        
        // 从开始时间到结束时间，确保每个月都有记录
        LocalDateTime current = startTime;
        while (!current.isAfter(endTime)) {
            String monthKey = String.format("%d-%02d", current.getYear(), current.getMonthValue());
            monthsToReturn.add(monthKey);
            
            // 移动到下个月
            current = current.plusMonths(1).withDayOfMonth(1);
        }
        
        // 只保留最近12个月
        if (monthsToReturn.size() > 12) {
            monthsToReturn = monthsToReturn.subList(monthsToReturn.size() - 12, monthsToReturn.size());
        }
        
        // 遍历所有月份，确保所有预警类型都有值
        Set<String> allAlertTypes = new HashSet<>();
        for (Map<String, Long> alertTypes : groupedByMonth.values()) {
            allAlertTypes.addAll(alertTypes.keySet());
        }
        
        // 转换为返回格式
        List<StatisticsRespVO.DailyAlertTypeCountVO> monthlyAlertTypeCounts = new ArrayList<>();
        
        // 转换日期格式，构建返回值
        for (String monthKey : monthsToReturn) {
            String[] parts = monthKey.split("-");
            int year = Integer.parseInt(parts[0]);
            int month = Integer.parseInt(parts[1]);
            
            StatisticsRespVO.DailyAlertTypeCountVO vo = new StatisticsRespVO.DailyAlertTypeCountVO();
            
            // 设置日期为月份的第一天
            vo.setDate(LocalDate.of(year, month, 1));
            
            // 获取该月的统计数据
            Map<String, Long> typeCounts = groupedByMonth.getOrDefault(monthKey, new HashMap<>());
            
            // 确保所有预警类型都有值
            for (String alertType : allAlertTypes) {
                typeCounts.putIfAbsent(alertType, 0L);
            }
            
            vo.setAlertTypeCounts(typeCounts);
            monthlyAlertTypeCounts.add(vo);
        }
        
        // 按日期排序
        monthlyAlertTypeCounts.sort(Comparator.comparing(StatisticsRespVO.DailyAlertTypeCountVO::getDate));
        
        return monthlyAlertTypeCounts;
    }
    
    /**
     * 获取指定时间范围内每天按告警级别和预警类型分组的预警数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每天按告警级别和预警类型分组的预警数量统计列表
     */
    @Override
    public List<StatisticsRespVO.AlertLevelTypeCountVO> getDailyAlertLevelTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内每天按告警级别和预警类型分组的预警数量
        List<Map<String, Object>> result = alertMapper.selectDailyAlertLevelTypeCountByCreateTimeBetween(startTime, endTime);
        
        // 获取所有预警类型
        Set<String> allAlertTypes = new HashSet<>();
        // 获取所有告警级别
        Set<String> allLevels = new HashSet<>();
        
        for (Map<String, Object> row : result) {
            String alertType = (String) row.get("alert_type");
            String level = (String) row.get("level");
            allAlertTypes.add(alertType);
            allLevels.add(level);
        }
        
        // 按日期和告警级别分组整理数据
        Map<String, Map<String, Map<String, Long>>> groupedByDateAndLevel = new HashMap<>();
        
        // 处理查询结果
        for (Map<String, Object> row : result) {
            String dateStr = row.get("date").toString();
            String alertType = (String) row.get("alert_type");
            String level = (String) row.get("level");
            Long count = ((Number) row.get("count")).longValue();
            
            // 按日期和告警级别分组
            groupedByDateAndLevel
                    .computeIfAbsent(dateStr, k -> new HashMap<>())
                    .computeIfAbsent(level, k -> new HashMap<>())
                    .put(alertType, count);
        }
        
        // 转换为返回格式
        List<StatisticsRespVO.AlertLevelTypeCountVO> alertLevelTypeCounts = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        
        // 收集时间范围内所有的日期
        Set<LocalDate> allDates = new HashSet<>();
        LocalDate currentDate = startTime.toLocalDate();
        LocalDate endDate = endTime.toLocalDate();
        
        while (!currentDate.isAfter(endDate)) {
            allDates.add(currentDate);
            currentDate = currentDate.plusDays(1);
        }
        
        // 为每个日期和告警级别创建记录
        for (LocalDate date : allDates) {
            String dateStr = date.format(formatter);
            
            // 获取该日期的数据，如果不存在则创建一个空的
            Map<String, Map<String, Long>> levelTypeCounts = groupedByDateAndLevel.getOrDefault(dateStr, new HashMap<>());
            
            // 确保所有告警级别都有值
            for (String level : allLevels) {
                Map<String, Long> typeCounts = levelTypeCounts.computeIfAbsent(level, k -> new HashMap<>());
                
                // 确保所有预警类型都有值，没有的设为0
                for (String alertType : allAlertTypes) {
                    typeCounts.putIfAbsent(alertType, 0L);
                }
                
                // 创建VO对象
                StatisticsRespVO.AlertLevelTypeCountVO vo = new StatisticsRespVO.AlertLevelTypeCountVO();
                vo.setDate(date);
                vo.setLevel(level);
                vo.setAlertTypeCounts(typeCounts);
                alertLevelTypeCounts.add(vo);
            }
        }
        
        // 按日期和告警级别排序
        alertLevelTypeCounts.sort(Comparator.comparing(StatisticsRespVO.AlertLevelTypeCountVO::getDate)
                .thenComparing(StatisticsRespVO.AlertLevelTypeCountVO::getLevel));
        
        return alertLevelTypeCounts;
    }
    
    /**
     * 获取指定时间范围内每天按告警级别和预警类型分组的预警数量（近30天）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每天按告警级别和预警类型分组的预警数量统计列表
     */
    @Override
    public List<StatisticsRespVO.AlertLevelTypeCountVO> getMonthlyAlertLevelTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 调用相同的处理方法，只是时间范围不同
        return getDailyAlertLevelTypeCount(startTime, endTime);
    }
    
    /**
     * 获取指定时间范围内按月按告警级别和预警类型分组的预警数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 按月按告警级别和预警类型分组的预警数量统计列表
     */
    @Override
    public List<StatisticsRespVO.AlertLevelTypeCountVO> getYearlyAlertLevelTypeCount(LocalDateTime startTime, LocalDateTime endTime) {
        // 查询数据库，获取指定时间范围内按月按告警级别和预警类型分组的预警数量
        List<Map<String, Object>> result = alertMapper.selectMonthlyAlertLevelTypeCountByCreateTimeBetween(startTime, endTime);
        
        // 获取所有预警类型
        Set<String> allAlertTypes = new HashSet<>();
        // 获取所有告警级别
        Set<String> allLevels = new HashSet<>();
        
        for (Map<String, Object> row : result) {
            String alertType = (String) row.get("alert_type");
            String level = (String) row.get("level");
            allAlertTypes.add(alertType);
            allLevels.add(level);
        }
        
        // 按年月和告警级别分组整理数据
        Map<String, Map<String, Map<String, Long>>> groupedByMonthAndLevel = new HashMap<>();
        
        // 处理查询结果
        for (Map<String, Object> row : result) {
            Integer year = ((Number) row.get("year")).intValue();
            Integer month = ((Number) row.get("month")).intValue();
            String alertType = (String) row.get("alert_type");
            String level = (String) row.get("level");
            Long count = ((Number) row.get("count")).longValue();
            
            // 组合年月键
            String monthKey = String.format("%d-%02d", year, month);
            
            // 按年月和告警级别分组
            groupedByMonthAndLevel
                    .computeIfAbsent(monthKey, k -> new HashMap<>())
                    .computeIfAbsent(level, k -> new HashMap<>())
                    .put(alertType, count);
        }
        
        // 准备返回数据的月份列表
        List<String> monthsToReturn = new ArrayList<>();
        
        // 从开始时间到结束时间，确保每个月都有记录
        LocalDateTime current = startTime;
        while (!current.isAfter(endTime)) {
            String monthKey = String.format("%d-%02d", current.getYear(), current.getMonthValue());
            monthsToReturn.add(monthKey);
            
            // 移动到下个月
            current = current.plusMonths(1).withDayOfMonth(1);
        }
        
        // 只保留最近12个月
        if (monthsToReturn.size() > 12) {
            monthsToReturn = monthsToReturn.subList(monthsToReturn.size() - 12, monthsToReturn.size());
        }
        
        // 转换为返回格式
        List<StatisticsRespVO.AlertLevelTypeCountVO> alertLevelTypeCounts = new ArrayList<>();
        
        // 转换日期格式，构建返回值
        for (String monthKey : monthsToReturn) {
            String[] parts = monthKey.split("-");
            int year = Integer.parseInt(parts[0]);
            int month = Integer.parseInt(parts[1]);
            
            // 获取该月的数据，如果不存在则创建一个空的
            Map<String, Map<String, Long>> levelTypeCounts = groupedByMonthAndLevel.getOrDefault(monthKey, new HashMap<>());
            
            // 确保所有告警级别都有值
            for (String level : allLevels) {
                Map<String, Long> typeCounts = levelTypeCounts.computeIfAbsent(level, k -> new HashMap<>());
                
                // 确保所有预警类型都有值，没有的设为0
                for (String alertType : allAlertTypes) {
                    typeCounts.putIfAbsent(alertType, 0L);
                }
                
                // 创建VO对象
                StatisticsRespVO.AlertLevelTypeCountVO vo = new StatisticsRespVO.AlertLevelTypeCountVO();
                // 设置日期为月份的第一天
                vo.setDate(LocalDate.of(year, month, 1));
                vo.setLevel(level);
                vo.setAlertTypeCounts(typeCounts);
                alertLevelTypeCounts.add(vo);
            }
        }
        
        // 按日期和告警级别排序
        alertLevelTypeCounts.sort(Comparator.comparing(StatisticsRespVO.AlertLevelTypeCountVO::getDate)
                .thenComparing(StatisticsRespVO.AlertLevelTypeCountVO::getLevel));
        
        return alertLevelTypeCounts;
    }
    
    /**
     * 获取所有按告警级别分组的预警数量
     *
     * @return 按告警级别分组的预警数量统计，key 为告警级别，value 为数量
     */
    @Override
    public Map<String, Long> getAllAlertLevelCount() {
        // 查询数据库，获取所有按告警级别分组的预警数量
        List<Map<String, Object>> result = alertMapper.selectAlertLevelCount();
        
        // 将结果转换为Map<String, Long>格式
        Map<String, Long> alertLevelCount = new HashMap<>();
        for (Map<String, Object> map : result) {
            String level = (String) map.get("level");
            Long count = ((Number) map.get("count")).longValue();
            alertLevelCount.put(level, count);
        }
        
        return alertLevelCount;
    }
    
    /**
     * 获取所有按告警级别和预警类型分组的预警数量
     *
     * @return 按告警级别和预警类型分组的预警数量统计，key 为告警级别，value 为预警类型和数量的映射
     */
    @Override
    public Map<String, Map<String, Long>> getAllAlertLevelTypeCount() {
        // 查询数据库，获取所有按告警级别和预警类型分组的预警数量
        List<Map<String, Object>> result = alertMapper.selectAlertLevelTypeCount();
        
        // 将结果转换为Map<String, Map<String, Long>>格式
        Map<String, Map<String, Long>> alertLevelTypeCount = new HashMap<>();
        
        // 处理查询结果
        for (Map<String, Object> row : result) {
            String level = (String) row.get("level");
            String alertType = (String) row.get("alert_type");
            Long count = ((Number) row.get("count")).longValue();
            
            // 按告警级别分组
            alertLevelTypeCount.computeIfAbsent(level, k -> new HashMap<>())
                    .put(alertType, count);
        }
        
        return alertLevelTypeCount;
    }
    
    /**
     * 获取所有告警级别为warning的各类型预警数量统计
     *
     * @return 各类型预警数量统计，key 为预警类型，value 为数量
     */
    @Override
    public Map<String, Long> getWarningLevelAlertCount() {
        // 查询数据库，获取所有告警级别为warning的各类型预警数量
        List<Map<String, Object>> result = alertMapper.selectAlertTypeCountByLevel("warning");
        
        // 将结果转换为Map<String, Long>格式
        Map<String, Long> alertTypeCount = new HashMap<>();
        for (Map<String, Object> map : result) {
            String alertType = (String) map.get("alert_type");
            Long count = ((Number) map.get("count")).longValue();
            alertTypeCount.put(alertType, count);
        }
        
        // 确保所有预警类型都有对应的条目，没有的设置为0
        alertTypeCount.putIfAbsent("voltage", 0L);
        alertTypeCount.putIfAbsent("currents", 0L);
        alertTypeCount.putIfAbsent("active_power", 0L);
        alertTypeCount.putIfAbsent("energy_consumption", 0L);
        alertTypeCount.putIfAbsent("temperature", 0L);
        
        return alertTypeCount;
    }
    
    /**
     * 获取所有告警级别为danger的各类型预警数量统计
     *
     * @return 各类型预警数量统计，key 为预警类型，value 为数量
     */
    @Override
    public Map<String, Long> getDangerLevelAlertCount() {
        // 查询数据库，获取所有告警级别为danger的各类型预警数量
        List<Map<String, Object>> result = alertMapper.selectAlertTypeCountByLevel("danger");
        
        // 将结果转换为Map<String, Long>格式
        Map<String, Long> alertTypeCount = new HashMap<>();
        for (Map<String, Object> map : result) {
            String alertType = (String) map.get("alert_type");
            Long count = ((Number) map.get("count")).longValue();
            alertTypeCount.put(alertType, count);
        }
        
        // 确保所有预警类型都有对应的条目，没有的设置为0
        alertTypeCount.putIfAbsent("voltage", 0L);
        alertTypeCount.putIfAbsent("currents", 0L);
        alertTypeCount.putIfAbsent("active_power", 0L);
        alertTypeCount.putIfAbsent("energy_consumption", 0L);
        alertTypeCount.putIfAbsent("temperature", 0L);
        
        return alertTypeCount;
    }
} 